package util

import (
	"aiRole/internal/dto/request"
	result "aiRole/internal/dto/reslult"
	"aiRole/internal/dto/response"
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gorilla/websocket"
	"github.com/spf13/viper"
	"io"
	"net"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

type AiCall struct {
}

func NewAiCall() AiCall {
	return AiCall{}
}

func (call AiCall) CallARS(audioURL string) (*response.QiniuASRResponse, error) {
	url := "https://openai.qiniu.com/v1/voice/asr"
	// 请求体
	body := map[string]interface{}{
		"model": "asr",
		"audio": map[string]string{
			"format": "asr",
			"url":    audioURL,
		},
	}
	// 转为 JSON
	jsonBody, err := json.Marshal(body)
	if err != nil {
		return nil, err
	}
	// 创建请求
	req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonBody))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+viper.GetString("qncloud.key"))
	// 发请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	// 读响应
	respBody, err := io.ReadAll(resp.Body)
	fmt.Println(string(respBody))
	if err != nil {
		return nil, err
	}
	// 解析 JSON
	var result response.QiniuASRResponse
	if err := json.Unmarshal(respBody, &result); err != nil {
		return nil, err
	}
	return &result, nil
}

// text: 文本
// voiceType:音色
// oos的key
//
// 文本转语音
func (call AiCall) WssStreamStream(text, voiceType, key string, wsFrontEnd *websocket.Conn, mu *sync.Mutex) {
	var addr = "openai.qiniu.com"
	var u = url.URL{Scheme: "wss", Host: addr, Path: "/v1/voice/tts"}
	input := setupInput(voiceType, "mp3", 1.5, text)
	var header = http.Header{
		"Authorization": []string{fmt.Sprintf("Bearer %s", viper.GetString("qncloud.key"))},
		"VoiceType":     []string{voiceType},
	}

	c, _, err := websocket.DefaultDialer.Dial(u.String(), header)
	if err != nil {
		fmt.Println("dial err:", err)
		return
	}
	defer c.Close()

	err = c.WriteMessage(websocket.BinaryMessage, input)
	if err != nil {
		fmt.Println("write message fail:", err.Error())
		return
	}

	pr, pw := io.Pipe()

	go func() {
		if err := UploadStream(pr, key, key); err != nil {
			fmt.Println("上传失败:", err)
		}
	}()

	for {
		_, message, err := c.ReadMessage()
		if err != nil {
			fmt.Println("read message fail:", err.Error())
			break
		}

		var resp response.RelayTTSResponse
		if err := json.Unmarshal(message, &resp); err != nil {
			fmt.Println("unmarshal fail:", err.Error())
			continue
		}

		data, err := base64.StdEncoding.DecodeString(resp.Data)
		if err != nil {
			fmt.Println("decode fail:", err.Error())
			continue
		}

		// 写入 pipe（上传用）
		if _, err := pw.Write(data); err != nil {
			fmt.Println("pipe写入失败:", err)
		}

		// 发送给前端实时播放，加锁
		if wsFrontEnd != nil {
			mu.Lock()
			if err := result.WsBinary(wsFrontEnd, data); err != nil {
				fmt.Println("前端发送失败:", err)
				break
			}
			mu.Unlock()
		}

		if resp.Sequence < 0 {
			pw.Close() // 上传结束
			break
		}
	}
}
func setupInput(voiceType string, encoding string, speedRatio float64, text string) []byte {
	params := &request.TTSRequest{
		Audio: request.Audio{
			VoiceType:  voiceType,
			Encoding:   encoding,
			SpeedRatio: speedRatio,
		},
		Request: request.Request{
			Text: text,
		},
	}
	resStr, _ := json.Marshal(params)
	return resStr
}

func (call AiCall) ChatCompletion(messages []request.Message, model string) (string, error) {
	url := fmt.Sprintf("%s/chat/completions", "https://openai.qiniu.com/v1")

	reqBody := request.ChatRequest{
		Model:     model,
		Messages:  messages,
		Stream:    false,
		MaxTokens: 40960,
	}

	bodyBytes, err := json.Marshal(reqBody)
	if err != nil {
		return "", err
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(bodyBytes))
	if err != nil {
		return "", err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", viper.GetString("qncloud.key")))

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	respBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("request failed: %s", string(respBytes))
	}

	var chatResp response.ChatResponse
	if err := json.Unmarshal(respBytes, &chatResp); err != nil {
		return "", err
	}

	if len(chatResp.Choices) == 0 {
		return "", fmt.Errorf("no choices returned")
	}

	return chatResp.Choices[0].Message.Content, nil
}

// ChatCompletionStream 发送流式请求
// model: 模型名称，例如 "deepseek-v3"
// messages: 当前消息
// onToken: 每接收到一段 token 调用此回调
func (call AiCall) ChatCompletionStream(messages []request.Message, model string, onToken func(string)) error {
	url := fmt.Sprintf("%s/chat/completions", "https://openai.qiniu.com/v1")
	apiKey := viper.GetString("qncloud.key")
	reqBody := map[string]interface{}{
		"model":      model,
		"messages":   messages,
		"stream":     true,
		"max_tokens": 4096,
	}

	bodyBytes, err := json.Marshal(reqBody)
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST", url, bytes.NewReader(bodyBytes))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		data, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("request failed: %s", string(data))
	}

	scanner := bufio.NewScanner(resp.Body)
	for scanner.Scan() {
		line := scanner.Text()
		if strings.HasPrefix(line, "data: ") {
			payload := strings.TrimPrefix(line, "data: ")
			if payload == "[DONE]" {
				break
			}
			var chunk response.StreamResponse
			if err := json.Unmarshal([]byte(payload), &chunk); err != nil {
				continue
			}
			if len(chunk.Choices) > 0 && chunk.Choices[0].Delta.Content != "" {
				onToken(chunk.Choices[0].Delta.Content)
			}
		}
	}

	if err := scanner.Err(); err != nil {
		return err
	}

	return nil
}
func (call AiCall) WssStreamStreamV2(text, voiceType, key string, writeCh chan response.WsMessage, mu *sync.Mutex) {
	addr := "openai.qiniu.com"
	u := url.URL{Scheme: "wss", Host: addr, Path: "/v1/voice/tts"}
	input := setupInput(voiceType, "mp3", 1.0, text)
	header := http.Header{
		"Authorization": []string{fmt.Sprintf("Bearer %s", viper.GetString("qncloud.key"))},
		"VoiceType":     []string{voiceType},
	}

	c, _, err := websocket.DefaultDialer.Dial(u.String(), header)
	if err != nil {
		fmt.Println("dial err:", err)
		return
	}
	defer c.Close()

	// 发送请求
	if err := c.WriteMessage(websocket.BinaryMessage, input); err != nil {
		fmt.Println("write message fail:", err)
		return
	}

	mu.Lock()
	for {
		// 设置读超时 5 秒
		c.SetReadDeadline(time.Now().Add(5 * time.Second))

		_, message, err := c.ReadMessage()
		if err != nil {
			if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
				fmt.Println("connection closed")
			}
			var e net.Error
			if errors.As(err, &e) && e.Timeout() {
				fmt.Println("read timeout, break loop")
			}
			break
		}

		var resp response.RelayTTSResponse
		if err := json.Unmarshal(message, &resp); err != nil {
			fmt.Println("unmarshal fail:", err)
			continue
		}

		data, err := base64.StdEncoding.DecodeString(resp.Data)
		if err != nil {
			fmt.Println("decode fail:", err)
			continue
		}

		// 推送给前端实时播放
		writeCh <- response.WsMessage{MessageType: websocket.BinaryMessage, Data: data}

		if resp.Sequence < 0 {
			// 结束
			break
		}
	}

	mu.Unlock()
}

func TTS(text, voiceType string) (string, error) {
	input := setupInput(voiceType, "mp3", 1.0, text)
	var addr = "openai.qiniu.com"
	var u = url.URL{Scheme: "wss", Host: addr, Path: "/v1/voice/tts"}
	var header = http.Header{
		"Authorization": []string{fmt.Sprintf("Bearer %s", viper.GetString("qncloud.key"))},
		"VoiceType":     []string{voiceType},
	}
	c, _, err := websocket.DefaultDialer.Dial(u.String(), header)
	if err != nil {
		fmt.Println("dial err:", err)
		return "", nil
	}
	defer c.Close()
	err = c.WriteMessage(websocket.BinaryMessage, input)
	if err != nil {
		fmt.Println("write message fail, err:", err.Error())
		return "", nil
	}
	count := 0
	key := time.Now().String()
	var audio []byte
	for {
		count++
		var message []byte
		_, message, err := c.ReadMessage()
		if err != nil {
			return "", err
		}

		var resp response.RelayTTSResponse
		err = json.Unmarshal(message, &resp)

		if err != nil {
			fmt.Println("unmarshal fail, err:", err.Error())
			continue
		}
		d, err := base64.StdEncoding.DecodeString(resp.Data)
		if err != nil {
			fmt.Println("decode fail, err:", err.Error())
		}
		audio = append(audio, d...)

		if resp.Sequence < 0 {
			//上传七牛云
			err := UploadStream(bytes.NewReader(audio), key, key)
			if err != nil {
				fmt.Println("上传失败:", err)
				return "", nil
			}

			break
		}
	}
	return key, nil
}
